package com.boarsoft.web.websocket;

import java.util.List;

import javax.websocket.OnError;
import javax.websocket.Session;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.boarsoft.bean.LogonI;
import com.boarsoft.bean.ReplyInfo;
import com.boarsoft.boar.auth.TokenAuth;
import com.boarsoft.cache.Cache;
import com.boarsoft.cache.aop.Cached;
import com.boarsoft.common.Util;

/**
 * Websocket不是必需的，因此不用注解配置
 * 
 * @author Mac_J
 *
 */
public class WebsocketServer implements WebsocketListener {
	private static final Logger log = LoggerFactory.getLogger(WebsocketServer.class);

	/** 通过Spring配置注入 */
	protected Cache cache;
	/** */
	protected TokenAuth tokenAuth;

	protected String usrWssGroup = "usr-wss";

	public WebsocketServer() {
		WebsocketEndpoint.addListener("init", this);
		WebsocketEndpoint.addListener("default", this);
	}

	@Override
	public void onOpen(Session session) {
		// 推送session
		WebsocketMessage m = new WebsocketMessage();
		m.setGroup("base");
		m.setCode("open");
		m.setData(session.getId());
		WebsocketEndpoint.send(m, session);
	}

	@Override
	public void onClose(Session session) {

	}

	@OnError
	public void onError(Session session, Throwable error) {

	}

	@Override
	public String getCode() {
		return "websocket";
	}

	/**
	 * 收到客户端消息后调用的方法
	 * 
	 * @param message
	 *            客户端发送过来的消息
	 * @param session
	 *            可选的参数
	 */
	@Override
	public void onMessage(WebsocketMessage wm, Session session) {
		String g = wm.getGroup();
		if ("init".equals(g)) {
			LogonI<?> lg = this.getLogon(wm.getToken());
			if (lg == null) {
				throw new IllegalStateException(//
						String.format("Token %s is exipred", wm.getToken()));
			}
			this.putUsrWss(lg.getCode(), session);
		} else if ("default".equals(g)) {
			this.send(wm);
		}
	}

	/**
	 * 到缓存中查找对应的用户信息，找不到再调RPC去统一认证验证此token
	 * 
	 * @param token
	 *            注解的默认index属性为0，表示以方法的第一个参数为key
	 * @return
	 */
	@SuppressWarnings("unchecked")
	@Cached(group = "token")
	protected LogonI<Object> getLogon(String token) {
		try {
			ReplyInfo<Object> ri = tokenAuth.check(token);
			return (LogonI<Object>) ri.getData();
		} catch (Exception e) {
			log.error("Error on get logon by token {}", token, e);
			return null;
		}
	}

	public void send(WebsocketMessage m) {
		List<String> rLt = m.getRecipients();
		if (rLt == null || rLt.isEmpty()) {
			return;
		}
		// 从缓存中获取userId对应的sessionId
		String sid = null;
		for (String r : rLt) {
			try {
				sid = (String) cache.get(usrWssGroup, r);
			} catch (Exception e) {
				log.warn("Can not get websocket session id of {}", r, e);
				continue;
			}
			if (Util.strIsEmpty(sid)) {
				continue;
			}
			int x = WebsocketEndpoint.send(m, sid);
			if (x == -1) {
				this.delUsrWss(r);
			}
		}
	}

	/**
	 * 更新usr-wss，注册用户u与sessionId的关系
	 * 
	 * @param userCode
	 * @param session
	 */
	public void putUsrWss(String userCode, Session session) {
		try {
			// Map<String, Object> hm = new HashMap<String, Object>();
			// hm.put("a", InetUtil.LOCAL_ADDR);
			// hm.put("s", session.getId());
			cache.put(usrWssGroup, userCode, session.getId());
		} catch (Exception e) {
			log.error("Error on put usr-wss.{}", userCode, e);
		}
	}

	/**
	 * 从usr-wss组中移除值为u的key，即解除用户u与websocket session的关系
	 * 
	 * @param u
	 *            recipient/userId
	 */
	public void delUsrWss(String u) {
		try {
			cache.remove(usrWssGroup, u);
		} catch (Exception e) {
			log.error("Error on remove usr-wss.{}", u, e);
		}
	}

	public Cache getCache() {
		return cache;
	}

	public void setCache(Cache cache) {
		this.cache = cache;
	}

	public TokenAuth getTokenAuth() {
		return tokenAuth;
	}

	public void setTokenAuth(TokenAuth tokenAuth) {
		this.tokenAuth = tokenAuth;
	}
}
